package base;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.*;

import units.*;

import pheromoneMap.MapVisualization;
import pheromoneMap.PheromoneMap;
import pheromoneMap.PheromoneType;

public class PheromoneMain implements Runnable {

	protected ProxyBot proxyBot;
	protected PheromoneMap pheromoneMap;
	private HashMap<Integer, AntUnit> antUnitMap = new HashMap<Integer, AntUnit>();
	private int peon_count;
	private int grunt_count;
	private int range_count;
	private int barracks_count;
	private int tower_count;
	private int lumbermill_count;
	private int blacksmith_count;
	public static Random m_gen = new Random(System.currentTimeMillis());

	public PheromoneMain(ProxyBot proxyBot) {
		this.proxyBot = proxyBot;
		this.peon_count = 0;
		this.grunt_count = 0;
		this.range_count = 0;
		this.tower_count = 0;

		this.barracks_count = 0;
		this.lumbermill_count = 0;
		this.blacksmith_count = 0;
	}

	public void run() {

		System.out.println("PheromoneMain: STARTING!!!!");

		String map = "maps/PheromoneCraft_Small.pud.gz";//"maps/NWTR-lite.pud.gz";////"maps/resource.pud.gz";//

		proxyBot.LoadMapAndRestartScenario(map);
		pheromoneMap = new PheromoneMap(proxyBot.GetMapWidth(), proxyBot
				.GetMapLength());

		MapVisualization mapVis = new MapVisualization(pheromoneMap);
		mapVis.setVisible(true);

		try {
			proxyBot.sendAndReceiveMessage("SPEED 2000", false);
			Thread.sleep(3000);
		} catch (InterruptedException e) {

		}

		long lastCycle = proxyBot.getCurrCycle();

		proxyBot.printMapCells();
		/*
		 * System.out.println( "The value for checkAdjacentTerrainType( 14, 9,
		 * 'T' )" + " should be true: " + proxyBot.checkAdjacentTerrainType( 14,
		 * 9, 'T')); System.out.println( "The value for
		 * checkAdjacentTerrainType( 9, 14, 'T' )" + " should be false: " +
		 * proxyBot.checkAdjacentTerrainType( 9, 14, 'T'));
		 * 
		 * System.out.println( "The value for checkAdjacentUnit( 5, 13, townhall )" + "
		 * should be true: " + proxyBot.checkAdjacentUnit( 5, 13,
		 * UnitType.HUMAN_TOWN_HALL ) ); System.out.println( "The value for
		 * checkAdjacentUnit( 10, 18, townhall )" + " should be true: " +
		 * proxyBot.checkAdjacentUnit( 10, 18, UnitType.HUMAN_TOWN_HALL ) );
		 */

		int count = 0;

		// int everyOtherCount = 0;
		// int typeUpdateCount = 0;

		PheromoneType[] types = PheromoneType.values();
		// int numOfTypes = types.length;
		// XXX: debug code, take me out ASAP!!!
		PrintStream outFile;
		PrintStream outFile2;
		
		try {
			outFile = new PrintStream(new FileOutputStream("unitPos.txt"));
			outFile2 = new PrintStream(new FileOutputStream("map2.txt"));
			
			System.out.println(proxyBot.getUnitTypeAt(31, 23).name());
			
			for(int i=0; i < proxyBot.GetMapLength(); i++)
			{
				for(int j=0; j < proxyBot.GetMapWidth(); j++)
				{
					outFile2.print(proxyBot.getUnitTypeAt(j, i).name() + " ");
				}
				outFile2.println();
			}
			
			while (true) {
				
				
				this.pheromoneMap.placeAttractionSquare(0, 0, PheromoneType.GO_AWAY, 5.0, proxyBot.GetMapWidth() - 1, proxyBot.GetMapLength() - 1);
				
				if (WargusUnit.getOnBarrack() == true)
					System.out.println("Can Build Barrack");
				if (WargusUnit.getOnFarm() == true)
					System.out.println("Can Build Farm");

				outFile.println("~~~~~~~~~~~~~~~~~~~~~~~~");
				int deltaT = (int) (proxyBot.getCurrCycle() - lastCycle);
				lastCycle += deltaT;

				try {

					if (count % 100 == 0) {
						for (int i = 0; i < proxyBot.GetMapWidth(); i++) {
							for (int j = 0; j < proxyBot.GetMapLength(); j++) {
								if (proxyBot.CheckMapCellTree(i, j)) {
									pheromoneMap.placeAttractionPheromone(i, j,
											PheromoneType.TO_WOOD, 1.0);
									pheromoneMap.placeRepulsionPheromone(i, j,
											PheromoneType.GO_AWAY, 5.0);
								} else if (proxyBot.CheckMapCellWall(i, j)) {
									pheromoneMap.placeRepulsionPheromone(i, j,
											PheromoneType.GO_AWAY, 10.0);
								}
							}
						}
					}

					synchronized (proxyBot.getNeutralUnits()) {
						ArrayList<WargusUnit> deepCopyNeutral = new ArrayList<WargusUnit>(
								proxyBot.getNeutralUnits());
						for (WargusUnit unit : deepCopyNeutral) {
							if (unit.getTypeEnum() == UnitType.GOLDMINE) {
								pheromoneMap.placeAttractionSquare(unit
										.getLocX(), unit.getLocY(),
										PheromoneType.TO_GOLD, 100.0, unit
										.getTypeEnum().getUnitWidth(),
										unit.getTypeEnum().getUnitHeight());
								pheromoneMap.placeRepulsionSquare(unit
										.getLocX(), unit.getLocY(),
										PheromoneType.GO_AWAY, 5.0, unit
										.getTypeEnum().getUnitWidth(),
										unit.getTypeEnum().getUnitHeight());
							}

						}
					}

					synchronized (proxyBot.getEnemyUnits()) {
						ArrayList<WargusUnit> deepCopyEnemy = new ArrayList<WargusUnit>(
								proxyBot.getEnemyUnits());
						for (WargusUnit unit : deepCopyEnemy) {
							if (!unit.IsDead()) {
								pheromoneMap.placeAttractionSquare(unit
										.getLocX(), unit.getLocY(),
										PheromoneType.ENEMY, 50.0, unit
										.getTypeEnum().getUnitWidth(),
										unit.getTypeEnum().getUnitHeight());
							}
						}
					}

					int tempPeonCount = 0;
					int tempGruntCount = 0;
					int tempRangeCount = 0;
					
					int tempBarracksCount = 0;

					int tempBlackSmithCount = 0;
					int tempLumberMillCount = 0;
					
					int tempTowerCount = 0;

					int loopCount = 0;
					synchronized (proxyBot.getMyUnits()) {
						ArrayList<WargusUnit> deepCopy = new ArrayList<WargusUnit>(
								proxyBot.getMyUnits());
						ArrayList<WargusUnit> queenUnits = new ArrayList<WargusUnit>();

						for (WargusUnit unit : deepCopy) {
							AntUnit temp = null;

							if ((unit.getTypeEnum() == UnitType.HUMAN_FOOTMAN || unit
									.getTypeEnum() == UnitType.ORC_GRUNT)
									&& (unit.IsDead() == false)) {
								Integer id = new Integer(unit.getUnitID());
								if (antUnitMap.containsKey(id)) {
									antUnitMap.get(id).setUnit(unit);
									temp = antUnitMap.get(id);

								} else {
									temp = antUnitMap.put(id, new SoldierUnit(
											proxyBot, this.pheromoneMap, unit));
								}

								tempGruntCount++;

							} 
							else if ((unit.getTypeEnum() == UnitType.HUMAN_ARCHER|| unit
									.getTypeEnum() == UnitType.ORC_AXETHROWER)
									&& (unit.IsDead() == false)) {
								Integer id = new Integer(unit.getUnitID());
								if (antUnitMap.containsKey(id)) {
									antUnitMap.get(id).setUnit(unit);
									temp = antUnitMap.get(id);
				
								} else {
									temp = antUnitMap.put(id, new SoldierUnit(
											proxyBot, this.pheromoneMap, unit));
								}

								tempRangeCount++;

							} 
							else if ((unit.getTypeEnum() == UnitType.HUMAN_PEASANT || unit
									.getTypeEnum() == UnitType.ORC_PEON)
									&& (unit.IsDead() == false)) {
								Integer id = new Integer(unit.getUnitID());
								if (antUnitMap.containsKey(id)) {
									antUnitMap.get(id).setUnit(unit);
									temp = antUnitMap.get(id);
									outFile.println("Unit(" + unit.getUnitID()
											+ "): xPos(" + unit.getLocX()
											+ ") yPos(" + unit.getLocY()
											+ ") :" + temp.getState() + " , "
											+ unit.getStatus()[0] + " , "
											+ unit.getRAmount());
								} else {
									temp = antUnitMap.put(id, new WorkerUnit(
											proxyBot, this.pheromoneMap, unit));
								}

								tempPeonCount++;
								// outFile.println("Unit(" + unit.getUnitID() +
								// "): xPos(" + unit.getLocX() + ") yPos(" +
								// unit.getLocY() + ") :" + temp.getState());
							} else if (unit.getTypeEnum() == UnitType.CORPSE) {
								Integer id = new Integer(unit.getUnitID());
								if (antUnitMap.containsKey(id)) {
									if (antUnitMap.get(id) instanceof WorkerUnit ||
											antUnitMap.get(id) instanceof SoldierUnit) {
										antUnitMap.put(id, new AntUnit(
												proxyBot, this.pheromoneMap, unit));
									}
								} else {
									antUnitMap.put(id, new AntUnit(
											proxyBot, this.pheromoneMap, unit));
								}
							} else if (unit.getTypeEnum() == UnitType.HUMAN_TOWN_HALL
									|| unit.getTypeEnum() == UnitType.HUMAN_KEEP
									|| unit.getTypeEnum() == UnitType.HUMAN_CASTLE) {

								queenUnits.add(unit);

								pheromoneMap.placeRepulsionSquare(unit
										.getLocX(), unit.getLocY(),
										PheromoneType.GO_AWAY, 5.0, unit
										.getTypeEnum().getUnitWidth(),
										unit.getTypeEnum().getUnitHeight());
								pheromoneMap.placeAttractionSquare(unit
										.getLocX(), unit.getLocY(),
										PheromoneType.MY_TERRITORY, 100.0, unit
										.getTypeEnum().getUnitWidth(),
										unit.getTypeEnum().getUnitHeight());

							} else if (unit.getTypeEnum() == UnitType.HUMAN_FARM
									|| unit.getTypeEnum() == UnitType.ORC_PIG_FARM) {

								pheromoneMap.placeRepulsionSquare(unit
										.getLocX(), unit.getLocY(),
										PheromoneType.GO_AWAY, 5.0, unit
										.getTypeEnum().getUnitWidth(),
										unit.getTypeEnum().getUnitHeight());
								pheromoneMap.placeAttractionSquare(unit
										.getLocX(), unit.getLocY(),
										PheromoneType.MY_TERRITORY, 100.0, unit
										.getTypeEnum().getUnitWidth(),
										unit.getTypeEnum().getUnitHeight());
							} else if (unit.getTypeEnum() == UnitType.HUMAN_BARRACKS
									|| unit.getTypeEnum() == UnitType.ORC_BARRACKS) {

								queenUnits.add(unit);
								tempBarracksCount++;
								pheromoneMap.placeRepulsionSquare(unit
										.getLocX(), unit.getLocY(),
										PheromoneType.GO_AWAY, 5.0, unit
										.getTypeEnum().getUnitWidth(),
										unit.getTypeEnum().getUnitHeight());
								;
								pheromoneMap.placeAttractionSquare(unit
										.getLocX(), unit.getLocY(),
										PheromoneType.MY_TERRITORY, 100.0, unit
										.getTypeEnum().getUnitWidth(),
										unit.getTypeEnum().getUnitHeight());
							} else if (unit.getTypeEnum() == UnitType.HUMAN_BLACKSMITH
									|| unit.getTypeEnum() == UnitType.ORC_BLACKSMITH) {

								queenUnits.add(unit);
								tempBlackSmithCount++;
								pheromoneMap.placeRepulsionSquare(unit
										.getLocX(), unit.getLocY(),
										PheromoneType.GO_AWAY, 5.0, unit
										.getTypeEnum().getUnitWidth(),
										unit.getTypeEnum().getUnitHeight());
								;
								pheromoneMap.placeAttractionSquare(unit
										.getLocX(), unit.getLocY(),
										PheromoneType.MY_TERRITORY, 100.0, unit
										.getTypeEnum().getUnitWidth(),
										unit.getTypeEnum().getUnitHeight());
							} else if (unit.getTypeEnum() == UnitType.HUMAN_ELVEN_LUMBER_MILL
									|| unit.getTypeEnum() == UnitType.ORC_TROLL_LUMBER_MILL) {

								queenUnits.add(unit);
								tempLumberMillCount++;
								pheromoneMap.placeRepulsionSquare(unit
										.getLocX(), unit.getLocY(),
										PheromoneType.GO_AWAY, 5.0, unit
										.getTypeEnum().getUnitWidth(),
										unit.getTypeEnum().getUnitHeight());
								;
								pheromoneMap.placeAttractionSquare(unit
										.getLocX(), unit.getLocY(),
										PheromoneType.MY_TERRITORY, 100.0, unit
										.getTypeEnum().getUnitWidth(),
										unit.getTypeEnum().getUnitHeight());
							}
							else if (unit.getTypeEnum() == UnitType.HUMAN_GUARD_TOWER
									|| unit.getTypeEnum() == UnitType.HUMAN_WATCH_TOWER
									|| unit.getTypeEnum() == UnitType.HUMAN_CANNON_TOWER) {

								queenUnits.add(unit);
								tempTowerCount++;
								
								//System.out.println("PheromoneMain: added human tower to queen");
								pheromoneMap.placeRepulsionSquare(unit
										.getLocX(), unit.getLocY(),
										PheromoneType.GO_AWAY, 5.0, unit
										.getTypeEnum().getUnitWidth(),
										unit.getTypeEnum().getUnitHeight());
								;
								pheromoneMap.placeAttractionSquare(unit
										.getLocX(), unit.getLocY(),
										PheromoneType.MY_TERRITORY, 100.0, unit
										.getTypeEnum().getUnitWidth(),
										unit.getTypeEnum().getUnitHeight());
							} 
							else {
								//System.out.println("Could not recognize this: " + unit.getTypeEnum().name());
							}

							loopCount++;
							if (deepCopy.size() == loopCount) {
								QueenUnit new_queen = new QueenUnit(proxyBot,
										this.pheromoneMap, unit, queenUnits);

								new_queen.setPeonCount(peon_count);
								new_queen.setGruntCount(grunt_count);
								new_queen.setRangeCount(range_count);
								
								new_queen.setBarracksCount(barracks_count);

								new_queen.setBlackSmithCount(blacksmith_count);
								new_queen.setLumberMillCount(lumbermill_count);
								new_queen.setTowerCount(tower_count);

								new_queen.updateState();
								new_queen.move();

							}

						}
					}

					peon_count = tempPeonCount;
					grunt_count = tempGruntCount;
					range_count = tempRangeCount;
					tower_count = tempTowerCount;
					
					barracks_count = tempBarracksCount;

					lumbermill_count = tempLumberMillCount;
					blacksmith_count = tempBlackSmithCount;

				} catch (ConcurrentModificationException e) {
					System.out.println("CME");
					e.printStackTrace();
					System.exit(-1);
				}

				for (AntUnit unit : this.antUnitMap.values()) {
					unit.updateState();
				}
				for (AntUnit unit : this.antUnitMap.values()) {
					unit.move();
				}

				for (PheromoneType type : types) {
					pheromoneMap.decay(type, 1);// deltaT * numOfTypes);
					pheromoneMap.diffuse(type, 1);// deltaT * numOfTypes);
					pheromoneMap.coalesce(type, 1);// deltaT * numOfTypes);

				}

				mapVis.repaint();
				
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}
